##
## Licensed to the .NET Foundation under one or more agreements.
## The .NET Foundation licenses this file to you under the MIT license.
##
##  This script exists to create a dummy implementation of the eventprovider
##  interface from a manifest file
##
##  The intended use if for platforms which support event pipe
##  but do not have a an eventing platform to receive report events

import os
from genEventing import *
from utilities import open_for_update

stdprolog_cpp="""
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

/******************************************************************

DO NOT MODIFY. AUTOGENERATED FILE.
This file is generated using the logic from <root>/src/scripts/genDummyProvider.py

******************************************************************/
"""

def trimProvName(name):
    name = name.replace("Windows-",'')
    name = name.replace("Microsoft-",'')
    name = name.replace('-','_')
    return name

def escapeProvFilename(name):
    name = name.replace('_','')
    name = name.lower()
    return name

def generateDummyProvider(providerName, eventNodes, allTemplates, runtimeFlavor, extern):
    impl = []
    for eventNode in eventNodes:
        eventName    = eventNode.getAttribute('symbol')
        templateName = eventNode.getAttribute('template')

        #generate EventXplatEnabled
        if extern: impl.append('extern "C" ')
        impl.append("BOOL  EventXplatEnabled%s(){ return FALSE; }\n\n" % (eventName,))

        #generate FireEtw functions
        fnptype = []
        linefnptype = []
        if extern: fnptype.append('extern "C" ')
        fnptype.append("ULONG  FireEtXplat")
        fnptype.append(eventName)
        fnptype.append("(\n")


        if templateName:
            template = allTemplates[templateName]
        else:
            template = None

        if template:
            fnSig   = template.signature
            for paramName in fnSig.paramlist:
                fnparam     = fnSig.getParam(paramName)
                wintypeName = fnparam.winType
                typewName   = getPalDataTypeMapping(runtimeFlavor)[wintypeName]
                winCount    = fnparam.count
                countw      = getPalDataTypeMapping(runtimeFlavor)[winCount]

                if paramName in template.structs:
                    linefnptype.append("%sint %s_ElementSize,\n" % (lindent, paramName))

                linefnptype.append(lindent)
                linefnptype.append(typewName)
                if countw != " ":
                    linefnptype.append(countw)

                linefnptype.append(" ")
                linefnptype.append(fnparam.name)
                linefnptype.append(",\n")

            if len(linefnptype) > 0 :
                del linefnptype[-1]

        fnptype.extend(linefnptype)
        fnptype.append(")\n{\n")
        impl.extend(fnptype)

        #start of fn body
        impl.append("    return ERROR_SUCCESS;\n")
        impl.append("}\n\n")

    return ''.join(impl)

def generateDummyFiles(etwmanifest, out_dirname, runtimeFlavor, extern, dryRun):
    tree                    = DOM.parse(etwmanifest)

    #keep these relative
    dummy_directory              = "dummy"
    dummyevntprovPre             = os.path.join(dummy_directory, "eventprov")

    if not os.path.exists(out_dirname):
        os.makedirs(out_dirname)

    if not os.path.exists(os.path.join(out_dirname, dummy_directory)):
        os.makedirs(os.path.join(out_dirname, dummy_directory))

    # Dummy Instrumentation
    for providerNode in tree.getElementsByTagName('provider'):
        providerName = trimProvName(providerNode.getAttribute('name'))
        providerName_File = escapeProvFilename(providerName)

        dummyevntprov = os.path.join(out_dirname, dummyevntprovPre + providerName_File + ".cpp")

        if dryRun:
            print(dummyevntprov)
        else:
            with open_for_update(dummyevntprov) as impl:
                impl.write(stdprolog_cpp + "\n")

                impl.write("""
#ifdef TARGET_UNIX
#include "pal_mstypes.h"
#include "pal_error.h"
#include "pal.h"
#include "pal/stackstring.hpp"
#endif


""")

                templateNodes = providerNode.getElementsByTagName('template')
                eventNodes = providerNode.getElementsByTagName('event')

                allTemplates = parseTemplateNodes(templateNodes)

                #create the implementation of eventing functions : dummyeventprov*.cp
                impl.write(generateDummyProvider(providerName, eventNodes, allTemplates, runtimeFlavor, extern) + "\n")

def main(argv):

    #parse the command line
    parser = argparse.ArgumentParser(description="Generates the Code required to instrument LTTtng logging mechanism")

    required = parser.add_argument_group('required arguments')
    required.add_argument('--man',  type=str, required=True,
                                    help='full path to manifest containing the description of events')
    required.add_argument('--intermediate', type=str, required=True,
                                    help='full path to eventprovider  intermediate directory')
    required.add_argument('--runtimeflavor', type=str,default="CoreCLR",
                                    help='runtime flavor')
    required.add_argument('--nonextern', action='store_true',
                                    help='if specified, will generate files to be compiled into the CLR rather than externaly' )
    required.add_argument('--dry-run', action='store_true',
                                    help='if specified, will output the names of the generated files instead of generating the files' )
    args, unknown = parser.parse_known_args(argv)
    if unknown:
        print('Unknown argument(s): ', ', '.join(unknown))
        return 1

    sClrEtwAllMan     = args.man
    intermediate      = args.intermediate
    runtimeFlavor     = RuntimeFlavor(args.runtimeflavor)
    extern            = not args.nonextern
    dryRun            = args.dry_run

    generateDummyFiles(sClrEtwAllMan, intermediate, runtimeFlavor, extern, dryRun)

if __name__ == '__main__':
    return_code = main(sys.argv[1:])
    sys.exit(return_code)
